<template>
  <div>
    <div class="content-container">
      <width-transition :value="!fullTable" flex>
        <template v-if="showLeft">
          <slot/>
        </template>
      </width-transition>

      <div class="content-container-right">

        <height-transition :value="!fullTable">
          <height-transition :value="openTopSlot">
            <div v-if="slots.top" class="filter-box">
              <slot name="top"/>
            </div>
          </height-transition>
          <el-form
              v-if="searchProps.length > 0"
              ref="queryFormRef"
              class="transition-container"
              :model="queryParams"
              :inline="true"
              :label-width="searchLabelWidth"
              @keydown.enter="handleQuery"
          >
            <height-transition :value="showSearch">
              <div class="filter-box">
                <template v-for="(item, index) in searchProps">
                  <el-form-item
                      v-if="item.type !== 'hidden'"
                      :key="index"
                      :label-width="item.labelWidth? item.labelWidth + 'rem' : null"
                      style="user-select: none;"
                      :label="item.label"
                      :prop="item.prop"
                  >
                    <el-input
                        v-if="item.type === 'input'"
                        v-model="queryParams[item.prop]"
                        :placeholder="item.placeholder || `请输入${item.label}`"
                        :style="{ width: item.width ? item.width + 'rem' : null }"
                        clearable
                        @clear="handleQuery"
                        @keyup.enter="handleQuery"
                    />
                    <el-select
                        v-if="item.type === 'select'"
                        v-model="queryParams[item.prop]"
                        :placeholder="item.placeholder || `-- 请选择${item.label} --`"
                        clearable
                        :style="{ width: item.width ? item.width + 'rem' : null }"
                        @change="handleQuery"
                    >
                      <el-option v-for="dict in item.options" :key="dict.value" :label="dict.label" :value="dict.value"/>
                    </el-select>
                    <el-cascader
                        v-if="item.type === 'cascader'"
                        v-model="queryParams[item.prop]"
                        :style="{ width: item.width ? item.width + 'rem' : null }"
                        :placeholder="item.placeholder || `-- 请选择${item.label} --`"
                        :options="item.options"
                        filterable
                        clearable
                        :props="item.props"
                        @change="handleQuery"
                    />
                    <el-date-picker
                        v-if="item.type === 'date'"
                        v-model="dateRange"
                        :style="{ width: `${item.width ? item.width : 15}rem` }"
                        value-format="YYYY-MM-DD"
                        type="daterange"
                        range-separator="-"
                        start-placeholder="开始日期"
                        end-placeholder="结束日期"
                        @change="handleQuery"
                    />
                  </el-form-item>
                </template>
                <el-form-item class="filter-box-btn-Placeholder"/>
                <el-form-item class="filter-box-btn">
                  <el-button type="primary" :icon="Search" @click="handleQuery">搜索</el-button>
                  <el-button :icon="Refresh" @click="resetQuery">重置</el-button>
                </el-form-item>
              </div>
            </height-transition>
          </el-form>
        </height-transition>

        <div class="content-box">
          <el-tabs
              v-if="tabValues.length > 0"
              v-model="curTab"
              class="mb10"
              style="user-select: none"
              @tab-change="handleQuery"
          >
            <el-tab-pane v-if="showTabAll" label="全部" name="all"/>
            <el-tab-pane v-for="item in tabValues" :key="item.value" :label="item.label" :name="item.value"/>
          </el-tabs>
          <el-row v-if="Object.keys(ops).length > 0 || showToolbar" :gutter="10" class="mb20">
            <el-col v-if="ops.hasOwnProperty('add')" :span="1.5">
              <el-button
                  v-hasPerm="[ops['add']]"
                  type="primary"
                  plain
                  :icon="Plus"
                  size="small"
                  @click="handleOps('add')"
              >新增
              </el-button>
            </el-col>
            <el-col v-if="ops.hasOwnProperty('update')" :span="1.5">
              <el-button
                  v-hasPerm="[ops['update']]"
                  type="success"
                  plain
                  :icon="Edit"
                  size="small"
                  :disabled="single"
                  @click="handleOps('update')"
              >修改
              </el-button>
            </el-col>
            <el-col v-if="ops.hasOwnProperty('delete')" :span="1.5">
              <el-button
                  v-hasPerm="[ops['delete']]"
                  type="danger"
                  plain
                  :icon="Delete"
                  size="small"
                  :disabled="multiple"
                  @click="handleOps('delete')"
              >删除
              </el-button>
            </el-col>
            <el-col v-if="ops.hasOwnProperty('import')" :span="1.5">
              <el-button
                  v-hasPerm="[ops['import']]"
                  type="warning"
                  plain
                  :icon="Upload"
                  size="small"
                  @click="handleOps('import')"
              >导入
              </el-button>
            </el-col>
            <el-col v-if="ops.hasOwnProperty('export')" :span="1.5">
              <el-button
                  v-hasPerm="[ops['export']]"
                  type="info"
                  plain
                  :icon="Download"
                  size="small"
                  @click="handleOps('export')"
              >导出
              </el-button>
            </el-col>
            <div v-if="slots.ops">
              <slot name="ops"/>
            </div>
            <div style="flex: 1"/>
            <customize-toolbar
                :options="showFullTButton?[fullButton,...toolbarOption]:toolbarOption"
            />
            <right-toolbar
                v-if="showToolbar"
                v-model:show-search="showSearch"
                :columns="columns"
                @query-table="getList"
                @disable-columns="(disabledColumns)=>columns=columns.map(v=>({...v,visible:!disabledColumns.includes(v.key)}))"
            />
          </el-row>
          <div v-if="slots.table">
            <slot name="table"/>
          </div>
          <el-table
              v-else
              ref="tableRef"
              v-loading="loading"
              :data="tableData"
              :row-key="rowKey"
              height="100%"
              @selection-change="handleSelectionChange"
          >
            <el-table-column
                v-if="showSelection"
                type="selection"
                width="50"
                align="center"
                :selectable="isSelectable"
            />
            <el-table-column v-if="tableExpand" type="expand">
              <template #default="scope">
                <slot name="expand" :row="scope.row"/>
              </template>
            </el-table-column>
            <template v-for="(item, index) in props.tableProps">
              <el-table-column
                  v-if="isVisible(item)"
                  :key="index"
                  :label="item.label"
                  :prop="item.prop"
                  align="center"
                  :width="item.width"
                  :fixed="item.fixed"
              >
                <template v-if="item.type" #default="scope">
                  <slot :name="`${item.type}_before`" :row="scope.row"/>
                  <el-button
                      v-if="item.type === 'operate' && rowOps.hasOwnProperty('update')"
                      v-hasPerm="[rowOps['update']]"
                      size="small"
                      class="el-button--text"
                      :icon="Edit"
                      @click="handleUpdate(scope.row)"
                  >修改
                  </el-button>
                  <slot :name="`${item.type}_center`" :row="scope.row"/>
                  <el-button
                      v-if="item.type === 'operate' && rowOps.hasOwnProperty('delete')"
                      v-hasPerm="[rowOps['delete']]"
                      size="small"
                      class="el-button--text"
                      :icon="Delete"
                      style="color: #F56C6C"
                      @click="handleDelete(scope.row)"
                  >删除
                  </el-button>
                  <slot :name="item.type" :row="scope.row"/>
                </template>
              </el-table-column>
            </template>
          </el-table>

          <pagination
              v-if="!slots.table"
              style="margin-top:2px;margin-bottom: 20px;"
              :total="total"
              v-model:page="queryParams.pageIndex"
              v-model:limit="queryParams.pageSize"
              @pagination="getList"
          />
        </div>
      </div>
    </div>
    <!-- 用户导入对话框 -->
    <el-dialog
        v-if="ops.hasOwnProperty('import')"
        :title="upload.title"
        v-model:visible="upload.open"
        width="400px"
        append-to-body
    >
      <el-upload
          ref="uploadRef"
          :limit="1"
          accept=".xlsx, .xls"
          :headers="upload.headers"
          :action="upload.url + '?updateSupport=' + upload.updateSupport"
          :disabled="upload.isUploading"
          :on-progress="handleFileUploadProgress"
          :on-success="handleFileSuccess"
          :auto-upload="false"
          drag
      >
        <el-icon>
          <Upload/>
        </el-icon>
        <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
        <template #tip>
          <div class="el-upload__tip text-center">
            <div class="el-upload__tip">
              <el-checkbox v-model="upload.updateSupport"/>
              是否更新已经存在的用户数据
            </div>
            <span>仅允许导入xls、xlsx格式文件。</span>
            <el-link
                type="primary"
                :underline="false"
                style="font-size:12px;vertical-align: baseline;"
                @click="importTemplate"
            >下载模板
            </el-link>
          </div>
        </template>
      </el-upload>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitFileForm">确 定</el-button>
          <el-button @click="upload.open = false">取 消</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import store from '@/store'
import indexProp from '@/layouts/content/ContentPanel/indexProp.js'
import { addDateRange } from '@/utils/index.js'
import { Delete, Download, Edit, FullScreen, Plus, Refresh, Search, Upload } from '@element-plus/icons-vue'

defineOptions({
  name: 'ContentPanel'
})

const props = defineProps({...indexProp})
const emits = defineEmits([
  // 新增按钮点击事件,返回左边栏id和当前tab值
  'handleAdd',
  // 修改按钮点击事件,返回当前行数据
  'handleUpdate',
  // 删除按钮点击事件,返回当前删除数据id
  'handleDelete',
  // tab切换事件,返回当前tab值
  'tabChange',
  // 多选框选中事件,返回选中的数据
  'handleSelectionChange',
  // 查询事件,返回查询参数
  'handleQuery',
  // 获取数据事件,返回查询参数
  'handleList',
  // 左边栏id切换事件,返回左边栏id
  'leftIdChange',
  // 左边栏切换事件,返回左边栏数据
  'leftChange'
])
const slots = useSlots()
const queryFormRef = ref("queryFormRef")
const tableRef = ref("tableRef")
const uploadRef = ref('uploadRef')
//---------------------------------------------------------------------
// 全屏显示
const showFullTButton = computed(() => {
  const conditions = [
    showLeft.value,
    !!slots.top,
    props.searchProps.length > 0
  ].filter(Boolean)
  // 如果true的数量>=2则显示全屏按钮
  return conditions.length >= 2
})
const fullTable = ref(false)
const fullButton = computed(() => ({
  label: ['复位', '表格最大化'],
  icon: FullScreen,
  value: fullTable.value,
  click: () => {
    fullTable.value = !fullTable.value
  }
}))
// 当前tab值
const curTab = ref(props.showTabAll ? 'all' : props.tabValues[0]?.value || '')
const showSearch = ref(props.showTopSearch)
// 当前左边栏id
const curLeftId = ref()
// 显示列
const columns = ref(props.tableProps.map((item, index) => ({key: index, label: item.label, visible: true})))
// 查询参数
const queryParams = ref({
  pageIndex: 1,
  pageSize: 10
})
// 日期范围
const dateRange = ref([])

// 遮罩层
const loading = ref(true)
// 总条数
const total = ref(0)
// 表格数据
const tableData = ref([])
// 多选框选中id数组
const ids = ref([])
// 多选框选择源数据数组
const tableSelectData = ref([])
// 非单个禁用
const single = ref(true)
// 非多个禁用
const multiple = ref(true)
// 用户导入参数
const upload = ref({
  // 是否显示弹出层（用户导入）
  open: false,
  // 弹出层标题（用户导入）
  title: '',
  // 是否禁用上传
  isUploading: false,
  // 是否更新已经存在的用户数据
  updateSupport: 0,
  // 设置上传的请求头部
  headers: {
    Authorization: `${ store.user.tokenName } ${ store.user.token }`
  },
  // 上传的地址
  url: import.meta.env.VITE_APP_BASE_API + props.importAndExport.importUrl
})

//---------------------------------------------------------------------
// 是否显示左侧列表
const showLeft = computed(() => {
  const leftName = ['left-list', 'LeftList']
  return slots.default?.()?.some(vnode =>
      vnode.type?.name && leftName.includes(vnode.type.name)
  ) ?? false
})
// 是否有固定列
const hasFixedTableColumn = computed(() => props.tableProps.some(v => v.fixed))
// 搜索条件变化时立即更新查询参数
watch(() => props.searchProps, newVal => newVal.forEach(item => queryParams.value[item.prop] = item.default), {immediate: true})
// 触发新增、修改、删除等操作
const handleOps = (type) => {
  if (type === 'import') {
    handleImport()
  } else if (type === 'export') {
    handleExport()
  } else if (type === 'delete') {
    handleDelete()
  } else if (type === 'update') {
    handleUpdate()
  } else {
    emits('handleAdd', {
      curTab: curTab.value === 'all' ? '' : curTab.value,
      curLeft: curLeftId.value
    })
  }
}
// 搜索按钮操作
const handleQuery = () => {
  queryParams.value.pageIndex = 1
  if (props.tabValues.length > 0) {
    emits('tabChange', curTab.value === 'all' ? '' : curTab.value)
    queryParams.value[props.tabProp] = curTab.value === 'all' ? '' : curTab.value
  }
  queryParams.value = addDateRange(queryParams.value, dateRange.value)
  getList()
  emits('handleQuery', queryParams.value)
}
// 重置按钮操作
const resetQuery = () => {
  queryFormRef.value?.resetFields()
  dateRange.value = []
  handleQuery()
}
// 触发加载数据
const getList = async () => {
  if (slots.table) {
    emits('handleList', queryParams.value)
  } else {
    if (props.showTabAll === false) queryParams.value[props.tabProp] = curTab.value === 'all' ? '' : curTab.value
    loading.value = true
    $xl.apis[props.listApi]({
      params: await props.wrapQueryParamFunc(queryParams.value)
    }).then(res => {
      if (res.data) {
        props.handleListData && (res.data.records.forEach(v => props.handleListData(v)))
        tableData.value = res.data.records
        total.value = res.data.total
        loading.value = false
        // 解决设置列固定后高度异常
        if (hasFixedTableColumn.value) {
          nextTick(() => tableRef.value?.doLayout())
        }
      } else {
        tableData.value = []
        total.value = 0
        loading.value = false
      }
    }).catch(err => $xl.modal.msgError(err))
  }
}
// 是否显示列
const isVisible = row => {
  const item = columns.value.find(v => v.label === row.label)
  return item ? item.visible : true
}
// 多选框选中数据
const handleSelectionChange = selection => {
  ids.value = selection.map(item => item.id)
  tableSelectData.value = [...selection]
  single.value = selection.length !== 1
  multiple.value = !selection.length
  emits('handleSelectionChange', selection)
}

// 修改按钮操作
const handleUpdate = (row) => {
  const contentId = row?.id || ids.value
  if (props.getApi === '') {
    emits('handleUpdate', contentId)
  } else {
    $xl.apis[props.getApi]({
      jointUrl: '/' + contentId
    }).then(response => {
      emits('handleUpdate', response.data)
    }).catch(err => $xl.modal.msgError(err))
  }
}

// 删除按钮操作
const handleDelete = (row) => {
  const contentIds = row?.id || ids.value
  if (props.deleteApi) {
    $xl.modal.confirm(`是否确认删除${ props.title }编号为"${ contentIds }"的数据项？`).then(() => {
      $xl.apis[props.deleteApi]({
        jointUrl: '/' + contentIds
      }).then(() => {
        getList()
        $xl.modal.msgSuccess('删除成功')
      }).catch(err => $xl.modal.msgError(err))
    }).catch(() => { })
  } else {
    emits('handleDelete', contentIds)
  }
}

// 导出按钮操作
const handleExport = async () => {
  await $xl.apis.download(props.importAndExport.exportUrl, {
    ...await props.wrapQueryParamFunc(queryParams.value)
  }, `${ props.title }数据_${ new Date().getTime() }.xlsx`)
}

// 导入按钮操作
const handleImport = () => {
  upload.value.title = props.title + '数据导入'
  upload.value.open = true
}

// 下载模板操作
const importTemplate = () => {
  $xl.apis.download(props.importAndExport.templateUrl, {}, `${ props.title }数据导入模板_${ new Date().getTime() }.xlsx`)
}

// 文件上传中处理
const handleFileUploadProgress = () => {
  upload.value.isUploading = true
}

// 文件上传成功处理
const handleFileSuccess = (response) => {
  upload.value.open = false
  upload.value.isUploading = false
  uploadRef.value.clearFiles()
  $xl.alert(`<div style="overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;">${ response.msg }</div>`, '导入结果', {dangerouslyUseHTMLString: true})
  getList()
}

// 提交上传文件
const submitFileForm = () => {
  uploadRef.value.submit()
}

// 收起顶部插槽
const openTopSlot = ref(Boolean(slots.top))
const toggleTopSlot = () => {
  openTopSlot.value = !openTopSlot.value
}

/** ********************************** 左侧列表相关 *****************************************/
// 左侧列表点击加载新数据
const loadNewRightData = (item, toRightRequestName, toRightRequestValue) => {
  queryParams.value[toRightRequestName] = item[toRightRequestValue]
  curLeftId.value = item.id
  emits('leftIdChange', item.id)
  emits('leftChange', item)
  handleQuery()
}

// 左边菜单数据为空时,关闭loading
const handleEmptySecondData = (toRightRequestName) => {
  emits('leftIdChange', null)
  emits('leftChange', null)
  curLeftId.value = null
  tableData.value = []
  total.value = 0
  ids.value = []
  tableSelectData.value = []
  loading.value = false
  queryParams.value[toRightRequestName] = ''
  handleQuery()
}
/** ******************************* 为父组件提供的方法 ***************************************/
// 获取选中的ids
const getSelectedIds = () => {
  return ids.value
}
const getSelectedData = () => {
  return tableSelectData.value
}
defineExpose({
  getSelectedIds,
  getSelectedData,
  getList,
  toggleTopSlot
})
//
/** ******************************* 提供给子组件的方法 ***************************************/
provide('loadNewRightData', loadNewRightData)
provide('loadNoData', handleEmptySecondData)

onMounted(() => {
  if (!showLeft.value) getList()
})
</script>
<style lang="scss" scoped>
@use '@/assets/styles/variables.module' as *;

.content-container {
  height: calc(100vh - #{$navbar-height});
  display: flex;
  padding: 15px 20px 15px;
  background-color: rgb(243, 245, 248);

  &-right {
    width: 60%;
    flex: 1;
    display: flex;
    flex-direction: column;

    .hide_top_slot {
      display: none;
    }

    .filter-box {
      background: #ffffff;
      margin-bottom: 15px;
      padding: 23px 10px 5px;
      box-sizing: border-box;
      border-radius: 5px;
      position: relative;

      .filter-box-btn-Placeholder {
        width: 186px;
        height: 30px;
        margin-right: 0;
      }

      .filter-box-btn {
        position: absolute;
        bottom: 5px;
        right: 10px;
        width: 186px;
        margin-right: 0;

        &.el-form-item--large {
          margin-bottom: 26px;
        }
      }
    }

    .content-box {
      overflow-y: auto;
      background: #ffffff;
      padding: 20px 20px 15px;
      border-radius: 5px;
      flex: 1;
      display: flex;
      flex-direction: column;

      :deep(.el-scrollbar__wrap) {
        overflow-x: hidden;
      }
    }
  }
}


.el-button--text {
  border-color: transparent;
  background: transparent;
  color: var(--el-color-primary);
}


.fixed-header + .app-main .content-container {
  height: 100vh;
}

.hasTagsView .app-main .content-container {
  height: calc(100vh - #{$navbar-height} - #{$tags-view-height});
}

:deep(.el-form-item__label) {
  font-weight: bolder;
}
</style>
